//
// Created by tianq on 25-1-4.
// divide and conquer: round-robin schedule
//
#include <cmath>
#include <iostream>
#include <vector>
#include <iomanip>
#include <ranges>
using namespace std;

int main() {
    int n; // 2^n players, 2^n-1 days
    cin >> n;

    const int vs = static_cast<int>(pow(2, n));
    //v: schedule table
    vector<vector<int> > v(vs, vector<int>(vs, 0));
    v[0][0] = 1;

    //s: current group size 2^s
    //this can be a recursive process
    for (int s = 0; s < n; s++) {
        const int bs = static_cast<int>(pow(2, s));
        for (int dx = 0; dx < bs; dx++) {
            for (int dy = 0; dy < bs; dy++) {
                // top left stay unchanged
                v[dx + bs][dy + bs] = v[dx][dy]; // bottom right
                v[dx + bs][dy] = v[dx][dy] + bs; // top right
                v[dx][dy + bs] = v[dx][dy] + bs; // bottom left
            }
        }
    }

    for (const auto &row: v) {
        for (const auto &col: row | views::drop(1))
            cout << setw(2) << col << " ";
        cout << endl;
    }
    return 0;
}
